#ifndef BASE_CMD_FLAGS_H
#define BASE_CMD_FLAGS_H
bool ParseFlags(int argc, char** argv);

#include <map>
#include <string>
#include "base/basic_types.h"

using std::map;
using std::string;

enum FlagType {
  FLAG_INT32 = 0,
  FLAG_INT64 = 1,
  FLAG_DOUBLE = 2,
  FLAG_BOOL = 3,
  FLAG_STRING = 4,
};

struct FlagValue {
  void* value;
  FlagType type;
  string desc;
};

class CmdFlags {
 public:
  static CmdFlags* Get();
  void AddInt(const string& name, int* i, const char* desc);
  void AddInt64(const string& name, int64* i, const char* desc);
  void AddDouble(const string& name, double* d, const char* desc);
  void AddBool(const string& name, bool* b, const char* desc);
  void AddString(const string& name, string* s, const char* desc);
  bool GetFlag(const string& name, FlagValue** v);

 private:
  static CmdFlags* flags;
  CmdFlags();
  map<string, FlagValue> allflags;
};

class CmdFlagRegister {
 public:
  CmdFlagRegister(const string& name, int* i, int def, const char* desc);
  CmdFlagRegister(const string& name, bool* b, bool def, const char* desc);
  CmdFlagRegister(const string& name, string* s, const char* def, const char* desc);
  CmdFlagRegister(const string& name, int64* i, int64 def, const char* desc);
  CmdFlagRegister(const string& name, double* d, double def, const char* desc);
};



#define DEFINE_int32(a, b, c) \
  namespace nsflags { \
    int FLAGS_##a; \
    CmdFlagRegister register_##a(#a, &FLAGS_##a, b, c); \
  } \
  using nsflags::FLAGS_##a; \

#define DECLARE_int32(a) \
  namespace nsflags { \
    extern int FLAGS_##a; \
  } \
  using nsflags::FLAGS_##a; \

#define DEFINE_int64(a, b, c) \
  namespace nsflags { \
    int64 FLAGS_##a; \
    CmdFlagRegister register_##a(#a, &FLAGS_##a, b, c); \
  } \
  using nsflags::FLAGS_##a; \

#define DECLARE_int64(a) \
  namespace nsflags { \
    extern int64 FLAGS_##a; \
  } \
  using nsflags::FLAGS_##a; \

#define DEFINE_double(a, b, c) \
  namespace nsflags { \
    double FLAGS_##a; \
    CmdFlagRegister register_##a(#a, &FLAGS_##a, b, c); \
  } \
  using nsflags::FLAGS_##a; \

#define DECLARE_double(a) \
  namespace nsflags { \
    extern double FLAGS_##a; \
  } \
  using nsflags::FLAGS_##a; \

#define DEFINE_bool(a, b, c) \
  namespace nsflags { \
    bool FLAGS_##a; \
    CmdFlagRegister register_##a(#a, &FLAGS_##a, b, c); \
  } \
  using nsflags::FLAGS_##a; \

#define DECLARE_bool(a) \
  namespace nsflags { \
    extern bool FLAGS_##a; \
  } \
  using nsflags::FLAGS_##a; \

#define DEFINE_string(a, b, c) \
  namespace nsflags { \
    string FLAGS_##a; \
    CmdFlagRegister register_##a(#a, &FLAGS_##a, b, c); \
  } \
  using nsflags::FLAGS_##a; \

#define DECLARE_string(a) \
  namespace nsflags { \
    extern string FLAGS_##a; \
  } \
  using nsflags::FLAGS_##a; \

#endif
